﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.IO;
using System.Xml.Serialization;

/**
 * Our Game, which is a Microsoft_Xna_Framework.
 */
public class Game : Microsoft.Xna.Framework.Game
{
    /**
     * Some hard-coded const-values, hopefully useful.
     */
#if XBOX360
    public static int kScreenWidth = 1024;
    public static int kScreenHeight = 576;
#else
    public static int kScreenWidth = 1024;
    public static int kScreenHeight = 576;
#endif

#if DEBUG
    public static Boolean debug = true;
    public static bool kConsoleOn = true;
#else
    public static Boolean debug = false;
    public static bool kConsoleOn = false;
#endif
    
    // Member vars here
    private static Game s_this = null;
    private GraphicsDeviceManager m_graphics;
    private EnvStack m_envStack;
    private AssetLibrary m_assetLibrary;
    private SpriteBatch m_spriteBatch;
    private Console m_console;
    private SoundManager m_soundManager;
    private StorageDevice m_storageDevice = null;

    /**
     * Get Singleton instance of this.
     */
    public static Game getGame()
    {
        if (s_this == null)
        {
            s_this = new Game();
        }
        return s_this;
    }

    /**
     * Get instace of EnvStack.
     */
    public EnvStack getEnvStack() { return m_envStack; }
    /**
     * Get instance of AssetLibrary
     */
    public AssetLibrary getAssetLibrary() { return m_assetLibrary; }

    /** Get instance of SoundManager
     */
    public SoundManager getSoundManager() { return m_soundManager; }
    /**
     * Get instance of SpriteBatch
     */
    public SpriteBatch getSpriteBatch() { return m_spriteBatch; }
    /**
     * Get instance of Console
     */
    public Console getConsole() { return m_console; }
    /**
     * Get instance of our GraphicsDeviceManager.
     */
    public GraphicsDeviceManager getGraphics() { return m_graphics; }
    /**
     * Accessors for StorageDevice
     */
    public StorageDevice storageDevice
    {
        get { return m_storageDevice; }
        set { m_storageDevice = value; }
    }

    /**
     * Game's Constructor.
     * Initializes various things.
     */
    private Game()
    {
        Window.Title = "Colossal Crisis";
        Window.AllowUserResizing = false;
        base.Content.RootDirectory = "Content";
        this.Content = base.Content;

        m_graphics = new GraphicsDeviceManager(this);
        m_graphics.PreferredBackBufferWidth = kScreenWidth;
        m_graphics.PreferredBackBufferHeight = kScreenHeight;
        //m_graphics.IsFullScreen = true;
        m_graphics.ApplyChanges();

        Components.Add(new GamerServicesComponent(this));
    }

    /**
     * Game class's init function as inherited from our parent.
     */
    protected override void Initialize()
    {
        base.Initialize();
    }

    public void saveData()
    {
        // TODO: Currently crashes program. Probably related to GamerServicesComponent above.

        if ((s_this.storageDevice != null) &&
            s_this.storageDevice.IsConnected)
        {
            SelectStorageDevice(null);
        }
        else
        {
            Guide.BeginShowStorageDeviceSelector(
                new AsyncCallback(SelectStorageDevice), null);
        }
    }

    private static void SelectStorageDevice(IAsyncResult result)
    {
        if ((result != null) && result.IsCompleted)
        {
            s_this.storageDevice = Guide.EndShowStorageDeviceSelector(result);
        }
    }

    private static void SaveUserData(IAsyncResult result)
    {
        if ((result != null) && result.IsCompleted)
        {
            s_this.storageDevice = Guide.EndShowStorageDeviceSelector(result);
        }
        // TODO: Figure out what needs saving, and add that here
        /*
        if ((s_this.storageDevice != null) &&
            s_this.storageDevice.IsConnected)
        {
            using (StorageContainer storageContainer =
                s_this.storageDevice.OpenContainer("ColossalCrisis"))
            {
                string highscoresPath = Path.Combine(storageContainer.Path,
                                                     "highscores.xml");
                if (File.Exists(highscoresPath))
                {
                    using (FileStream file =
                        File.Open(highscoresPath, FileMode.Open))
                    {
                        XmlSerializer serializer =
                            new XmlSerializer(typeof(List<int>));
                        HighScores = (List<int>)serializer.Deserialize(file);
                    }
                }
            }
        }
        */
    }

    /**
     * Load graphics here
     */
    protected override void LoadContent()
    {
        m_spriteBatch = new SpriteBatch(GraphicsDevice);
        m_console = new Console(Content);
        HUD.loadFonts(Content);
        m_assetLibrary = new AssetLibrary();
        m_soundManager = new SoundManager();
        m_assetLibrary.loadAssetImagesFromDisk(Content);
        m_assetLibrary.loadSoundAndMusic(Content);

        m_envStack = new EnvStack();
        m_envStack.push(new MenuBase());


        base.LoadContent();
    }

    /**
     * Update as inherited from our parent.
     * Updates our EnvironmentStack, which in turn
     * updates all other functionality.
     * @param dt
     */

    
    protected override void Update(GameTime dt)
    {
        if (IsActive && !Guide.IsVisible)
        {
            if (!m_envStack.update(dt.ElapsedGameTime.TotalMilliseconds))
            {
                Exit();
            }
            m_console.update(dt.ElapsedGameTime.TotalMilliseconds);
        }
        base.Update(dt);
    }

    /**
     * Draw as inherited from our parent.
     * Draws our EnvironmentStack, which in turn
     * draws all other drawable things.
     * @param dt
     */
    protected override void Draw(GameTime dt)
    {
        if (Guide.IsVisible || IsActive)
        {
            // Note: This clear color determines our fadeTo color currently.
            m_graphics.GraphicsDevice.Clear(Color.Black);
            m_spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.BackToFront, SaveStateMode.None);
            m_envStack.render();
            m_console.render();
            m_spriteBatch.End();
        }
        base.Draw(dt);
    }

    protected override void OnExiting(object sender, EventArgs args)
    {
        base.OnExiting(sender, args);
    }
}
